import md5 from "blueimp-md5"

export type PromiseId = string
export type PromiseCallbacks<Data> = {
  resolve: (v: Data) => void,
  reject: (e: any) => void,
}
export type PromiseCallbacksPool<Data> = {
  [key in PromiseId]?: PromiseCallbacks<Data>[]
}

export class PromiseInOne<Data = any> {
  private promisePool: PromiseCallbacksPool<Data> = {}

  private genPromiseId(type: string, args: any): PromiseId {
    return type + md5(JSON.stringify(args))
  }

  intoPool(type: string, args: any, resolve: (v: Data) => void, reject: (e: any) => void): [string, boolean] {
    const promiseId = this.genPromiseId(type, args)
    const existed = !!this.promisePool[promiseId]
    if (!existed)
      this.promisePool[promiseId] = [{ resolve, reject }]
    else
      this.promisePool[promiseId]?.push({ resolve, reject })
    return [promiseId, existed]
  }

  rejectPromise(promiseId: PromiseId, e: any) {
    this.promisePool[promiseId]?.forEach(v => v.reject(e))
    delete this.promisePool[promiseId]
  }

  resolvePromise(promiseId: PromiseId, d: Data) {
    this.promisePool[promiseId]?.forEach(v => v.resolve(d))
    delete this.promisePool[promiseId]
  }

  async handlePromise(promiseId: PromiseId, promise: Promise<Data>) {
    try {
      const reply = await promise
      return this.resolvePromise(promiseId, reply)
    } catch (err) {
      return this.rejectPromise(promiseId, err)
    }
  }
}